Flutter PlatformViewsController
PlatformViewsController 是 Flutter 内嵌原生视图能力在 Android 的管理类。
PlatformViewsChannel 只负责接收和解析消息,但不包含处理逻辑。处理逻辑都转发到 PlatformViewsController 来进行实际处理。另外一点,不论是 Virtual displays 模式还是 Hybrid composition 模式,底层都由 PlatformViewsController 统一处理。
除了嵌原生视图之外,该类还负责外接纹理的纹理管理。
核心成员
PlatformViewsController 类成员都是重量级选手:
成员 | 类型 | 说明 | 备注 |
---|---|---|---|
registry | PlatformViewRegistryImpl | 所有平台视图的注册表 | |
androidTouchProcessor | AndroidTouchProcessor | Android 手势处理器 | |
context | Context | Android Context | |
flutterView | FlutterView | Android FlutterView,用于展示 Flutter UI 的视图 | |
textureRegistry | TextureRegistry | 纹理注册表 | |
textInputPlugin | TextInputPlugin | Flutter 在 Android 侧的输入插件 | |
platformViewsChannel | PlatformViewsChannel | 与 Flutter 通信的 Channel | 参见笔记《Flutter PlatformViewsChannel》 |
accessibilityEventsDelegate | AccessibilityEventsDelegate | Semantic 辅助功能相关 | |
vdControllers | HashMap<Integer, VirtualDisplayController> |
VirtualDisplay 的注册表 | VirtualDisplayController :是用于管理虚拟显示的控制器 |
contextToPlatformView | HashMap<Context, View> |
虚拟显示中的实际视图 | 键是Context 对象,值是View 对象。每个虚拟显示都有一个唯一的Context 。View 是Android中的视图,这里特指平台视图。这个映射用于根据Context 查找在同一个虚拟显示中的平台视图。 |
platformViews | SparseArray<PlatformView> |
Hybrid composition 模式下的平台视图 | |
platformViewParent | SparseArray<FlutterMutatorView> |
HC 平台视图的父视图 | 这是一个SparseArray ,它存储了FlutterMutatorView 对象。FlutterMutatorView 是一个特殊的视图,它可以对其子视图(即平台视图)应用一些操作,如变换矩阵或设置透明度。 |
overlayLayerViews | SparseArray<FlutterImageView> |
HC 平台视图的 Overlay UI | 这也是一个SparseArray ,它存储了FlutterImageView 对象。FlutterImageView 是一个视图,它可以显示一个 Flutter 渲染的图像。 |
nextOverlayLayerId | int | 用于生成下一个图层的唯一ID | 默认值为 0 |
flutterViewConvertedToImageView | boolean | 跟踪 flutterView 是否已经被转换为 FlutterImageView | 默认值为 false |
synchronizeToNativeViewHierarchy | boolean | 设置是否在添加平台视图时,将 flutterView的渲染表面转换为FlutterImageView | 默认值 true |
currentFrameUsedOverlayLayerIds | HashSet<Integer> |
储了在当前帧中显示的图层的ID | |
currentFrameUsedPlatformViewIds | HashSet<Integer> |
储了在当前帧中显示的平台视图的ID | |
motionEventTracker | MotionEventTracker | 获取原始的触摸事件 |
PlatformViewsHandler
除了上述成员外,还有一个 PlatformViewsHandler,它实现了 PlatformViewsChannel 的 PlatformViewsHandler 接口,参见《Flutter PlatformViewsChannel#PlatformViewsHandler 接口》。
其功能是,PlatformViewsChannel 收到 Flutter 侧操作请求后,通过该类转到 PlatformViewsController 中处理。
channelHandler 属性是你个匿名内部类:
private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
new PlatformViewsChannel.PlatformViewsHandler() {
@Override
public void createAndroidViewForPlatformView(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
//...
}
@Override
public void disposeAndroidViewForPlatformView(int viewId) {
//..
}
//...
}
上面代码仅用于释义,channelHandler 内部类实现了 PlatformViewsHandler 接口。这些接口的实现逻辑非常关键,将在后面小节中介绍。
Virtual displays 模式
createVirtualDisplayForPlatformView 创建
首先看 PlatformViewsHandler 的 Virtual displays 模式下创建原生视图的过程:
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public long createVirtualDisplayForPlatformView(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
// 省略一些校验逻辑...
// 解码创建参数
Object createParams = null;
if (request.params != null) {
createParams = viewFactory.getCreateArgsCodec().decodeMessage(request.params);
}
// 屏幕尺寸
int physicalWidth = toPhysicalPixels(request.logicalWidth);
int physicalHeight = toPhysicalPixels(request.logicalHeight);
validateVirtualDisplayDimensions(physicalWidth, physicalHeight);
// 创建 SurfaceTexture
TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture();
// 创建 Flutter 控制 VirtualDisplay 的控制器
VirtualDisplayController vdController =
VirtualDisplayController.create(
context,
accessibilityEventsDelegate,
viewFactory,
textureEntry,
physicalWidth,
physicalHeight,
request.viewId,
createParams,
(view, hasFocus) -> {
if (hasFocus) {
platformViewsChannel.invokeViewFocused(request.viewId);
}
});
// ...
// If our FlutterEngine is already attached to a Flutter UI, provide that Android
// View to this new platform view.
if (flutterView != null) {
vdController.onFlutterViewAttached(flutterView);
}
vdControllers.put(request.viewId, vdController);
View platformView = vdController.getView();
platformView.setLayoutDirection(request.direction);
// 这里还对 Context 有所采集,需要注意
contextToPlatformView.put(platformView.getContext(), platformView);
// 返回纹理 id
return textureEntry.id();
}
其中,textureRegistry.createSurfaceTexture
实现类位于 FlutterRenderer
,创建了一个 SurfaceTexture 实例,并将其注册进 FlutterEngine 中:
/**
* Creates and returns a new {@link SurfaceTexture} managed by the Flutter engine that is also
* made available to Flutter code.
*/
@Override
public SurfaceTextureEntry createSurfaceTexture() {
Log.v(TAG, "Creating a SurfaceTexture.");
final SurfaceTexture surfaceTexture = new SurfaceTexture(0);
return registerSurfaceTexture(surfaceTexture);
}
/**
* Registers and returns a {@link SurfaceTexture} managed by the Flutter engine that is also made
* available to Flutter code.
*/
@Override
public SurfaceTextureEntry registerSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) {
surfaceTexture.detachFromGLContext();
final SurfaceTextureRegistryEntry entry =
new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture);
Log.v(TAG, "New SurfaceTexture ID: " + entry.id());
registerTexture(entry.id(), entry.textureWrapper());
return entry;
}
其中,SurfaceTexture 是 Android 系统提供的底层图形渲染组件,其功能为:
Android 的 SurfaceTexture 提供了一种高效的方法,通过 OpenGL ES 将图像流中的帧捕获并作为纹理渲染。这意味着,您可以将来自摄像头、视频文件或其他图像流的帧直接渲染到OpenGL环境中,而不需要进行复杂的数据转换或处理。这样做的好处是能够实现高性能和低延迟的图像处理和显示,非常适合需要实时视频处理的应用,比如视频聊天、增强现实(AR)应用等。
Flutter VirtualDisplayController 是专门负责 Android VirtualDisplay 逻辑的控制器(详情可点击阅读 Flutter VirtualDisplayController ),在 Flutter VirtualDisplayController 的构造函数中会创建 Flutter SingleViewPresentation,在 Presentation 内部会真正创建原生视图。
vdController.onFlutterViewAttached(flutterView);
这步,Flutter VirtualDisplayController 实现逻辑为:
/** See {@link PlatformView#onFlutterViewAttached(View)} */
/*package*/ void onFlutterViewAttached(@NonNull View flutterView) {
if (presentation == null || presentation.getView() == null) {
return;
}
presentation.getView().onFlutterViewAttached(flutterView);
}
Flutter SingleViewPresentation 的 getView()
将返回 PlatformView,PlatformView 是供开发者在 Native 侧创建的原生视图类。给原生视图一个时机,获取到当前容器的 FlutterView。代码中有一个判断分支,引擎与 FlutterView 不总是绑定状态,当 App 切后台后,两者将会解绑。如果是后台状态下创建的平台视图,这个回调将会在未来返回前台后调用。
detach
这个方法的主要作用是断开PlatformViewsController
的连接,通常在Flutter应用程序切换到后台运行或被销毁时调用。
断开后,将停止处理平台视图消息,销毁所有的覆盖层表面,以及释放对Android上下文对象和纹理注册表的引用。
@UiThread
public void detach() {
if (platformViewsChannel != null) {
platformViewsChannel.setPlatformViewsHandler(null);
}
destroyOverlaySurfaces();
platformViewsChannel = null;
context = null;
textureRegistry = null;
}
Usage:
- PlatformViewsController.detach
- FlutterPluginRegistry.detach
- FlutterNativeView.detach
- 已废弃
- FlutterNativeView.detach
- FlutterEngineConnectionRegistry.detachFromActivityInternal
- FlutterPluginRegistry.detach
detachFromView
detachFromView
方法的作用是将PlatformViewsController
和其FlutterEngine
从渲染Flutter UI的Android View
中分离,包括销毁所有的覆盖层表面,从Flutter视图中移除所有的覆盖层视图,以及通知所有的VirtualDisplayController
对象Flutter视图已经被分离。
这个方法的主要作用是将PlatformViewsController
和其FlutterEngine
从渲染Flutter UI的Android View
中分离。
public void detachFromView() {
destroyOverlaySurfaces();
removeOverlaySurfaces();
this.flutterView = null;
flutterViewConvertedToImageView = false;
// Inform all existing platform views that they are no longer associated with
// a Flutter View.
for (VirtualDisplayController controller : vdControllers.values()) {
controller.onFlutterViewDetached();
}
}
其中:
- 将 flutterView 置空了
- flutterViewConvertedToImageView 也设置为了 False
FlutterMutatorView 声明周期管理
FlutterMutatorView 是 Hybrid composition 模式下,用于封装 PlatformView 的布局。
在 PlatformViewsController 中,有一个 SparseArray 列表进行管理:
// The platform view parents that are appended to `FlutterView`.
// If an entry in `platformViews` doesn't have an entry in this array, the platform view isn't
// in the view hierarchy.
//
// This view provides a wrapper that applies scene builder operations to the platform view.
// For example, a transform matrix, or setting opacity on the platform view layer.
//
// This is only applies to hybrid composition.
private final SparseArray<FlutterMutatorView> platformViewParent;
创建时机 initializePlatformViewIfNeeded:
/**
* Initializes a platform view and adds it to the view hierarchy.
*
* @param viewId The view ID. This member is not intended for public use, and is only visible for
* testing.
*/
@VisibleForTesting
void initializePlatformViewIfNeeded(int viewId) {
final PlatformView platformView = platformViews.get(viewId);
// ...
// 创建 FlutterMutatorView 实例
final FlutterMutatorView parentView =
new FlutterMutatorView(
context, context.getResources().getDisplayMetrics().density, androidTouchProcessor);
parentView.setOnDescendantFocusChangeListener(
(view, hasFocus) -> {
if (hasFocus) {
platformViewsChannel.invokeViewFocused(viewId);
} else if (textInputPlugin != null) {
textInputPlugin.clearPlatformViewClient(viewId);
}
});
// 添加到 platformViewParent
platformViewParent.put(viewId, parentView);
// 将 FlutterMutatorView 添加到它的父布局中
parentView.addView(platformView.getView());
flutterView.addView(parentView);
}
FlutterMutatorView 什么时候从父布局中删除的?
本文作者:Maeiee
本文链接:Flutter PlatformViewsController
版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!
喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!